package middleware

import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
	"tieup/internal/config"
	"tieup/pkg/redis"
)

// 提取Token的函数
func extractToken(c *gin.Context) string {
	// 1. 从Authorization头获取
	authHeader := c.GetHeader("Authorization")
	if authHeader != "" {
		parts := strings.Split(authHeader, " ")
		if len(parts) == 2 && parts[0] == "Bearer" {
			return parts[1]
		}
	}

	// 2. 从查询参数获取
	if token := c.Query("token"); token != "" {
		return token
	}

	// 3. 从cookie获取
	if token, err := c.Cookie("auth_token"); err == nil {
		return token
	}

	return ""
}

// 认证中间件
func AuthMiddleware(cfg config.AuthConfig) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取请求方法和路径
		method := c.Request.Method
		path := c.Request.URL.Path
		fullPath := c.FullPath() // 获取注册的路由路径（可能包含路径参数）

		// 打印请求信息
		fmt.Printf("==> 请求开始: %s %s [路由: %s]\n", method, path, fullPath)

		tokenString := extractToken(c)
		if tokenString == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Authorization token required"})
			return
		}

		// 检查Redis中是否存在此token（用于实现黑名单）
		ctx := context.Background()
		_, err := redis.Client.Get(ctx, "blacklist:"+tokenString).Result()
		if err == nil {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Token revoked"})
			return
		}

		// 解析并验证JWT
		token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(cfg.SecretKey), nil
		})

		if err != nil || !token.Valid {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
			return
		}

		// 从声明中提取用户ID
		if claims, ok := token.Claims.(jwt.MapClaims); ok {
			if userID, ok := claims["sub"].(float64); ok {
				c.Set("userID", uint(userID))
			} else {
				c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token claims"})
				return
			}
		}

		c.Next()
	}
}

// 登出时撤销token
func InvalidateToken(c *gin.Context, secretKey string, tokenExpiration time.Duration) {
	tokenString := extractToken(c)
	if tokenString != "" {
		ctx := context.Background()
		// 将token添加到黑名单，过期时间为token剩余有效时间
		expiration := time.Until(time.Now().Add(tokenExpiration))
		redis.Client.Set(ctx, "blacklist:"+tokenString, "1", expiration)
	}
}
